using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;

namespace WGT
{
    public partial class Dialog
    {
        #region MODE enum

        [Flags]
        public enum MODE
        {
            ERASE = 1,
            SHOW = 2,
            UPDATE = ERASE | SHOW,
            EVENT = 4
        }

        #endregion

        private bool bUpdate;
        public string[] event_args;

        private int iOld;
        protected MODE mode;
        private ArrayList qN = new ArrayList();
        private ArrayList qO = new ArrayList();
        private string sender;

        protected void GetPut<T>(ref T pbOld, ref T pbNew)
        {
            if ((mode & MODE.ERASE) > 0 || mode == MODE.EVENT)
                pbOld = (T) qO[iOld++];
            if ((mode & MODE.SHOW) > 0) qN.Add(pbNew);
        }

        protected void deAssertSync(int w)
        {
            int oldw = w;
            GetPut(ref oldw, ref w);
            Debug.Assert(oldw == w);
        }

        private bool Ifutil(bool bTest)
        {
            bool rval = false;
            bool bOldTest = false;

            GetPut(ref bOldTest, ref bTest);
            if (mode == MODE.ERASE || mode == MODE.EVENT) rval = bOldTest;
            else if (mode == MODE.SHOW) rval = bTest;
            else
            {
                if (bTest == bOldTest) rval = bTest;
                else
                {
                    rval = true;
                    mode = (bTest ? MODE.SHOW : MODE.ERASE);
                }
            }
            return rval;
        }

        protected void IF(Func<bool> expr, Action action)
        {
            MODE savemode = mode;
            if (Ifutil(P(expr))) action();
            mode = savemode;
        }

        protected void IF(Func<bool> expr, Action act, Action els)
        {
            MODE savemode = mode;
            bool DidIt = expr();
            if (Ifutil(P(() => DidIt))) act();
            mode = savemode;
            if (Ifutil(P(() => !DidIt))) els();
            mode = savemode;
        }

        protected void SWITCH<T>(T val, Dictionary<T, Action> map)
        {
            foreach (var @case in map)
            {
                IF(() => Equals(val, @case.Key),
                   () =>
                       {
                           @case.Value();
                           return;
                       });
            }
        }

        protected void FOR(Func<int> init, Func<bool> test, Func<int> incr, Action action)
        {
            MODE svmode = mode;
            for (init(); Ifutil(P(test)); incr())
            {
                action();
            }
            mode = svmode;
        }

        public void OnCommand(string id)
        {
            sender = id;
            bUpdate = false;
            Run(MODE.EVENT);
            if (bUpdate)
            {
                Run(MODE.UPDATE);
            }
            bUpdate = false;
        }

        public void Run(MODE _md)
        {
            oReset();
            mode = _md;

            HandleThrow(View);

            if (mode == MODE.EVENT)
                oReset();
            else
                oSwap();

            mode = MODE.UPDATE;
        }

        [DebuggerNonUserCode]
        protected void DD_THROW()
        {
            throw new DDThrow();
        }

        private static void HandleThrow(Action view)
        {
            try
            {
                view();
            }
            catch (DDThrow ex)
            {
            }
            catch (Exception ex)
            {
                Debug.Assert(false, ex.Message);
            }
        }

        #region Protect function

        // protect for value types
        protected bool P(Func<bool> expr)
        {
            return mode != MODE.ERASE ? expr() : false;
        }

        protected int P(Func<int> expr)
        {
            return mode != MODE.ERASE ? expr() : 0;
        }

        protected DateTime P(Func<DateTime> expr)
        {
            return mode != MODE.ERASE ? expr() : DateTime.MinValue;
        }

        // generic protect for reference types
        protected T P<T>(Func<T> func) where T : class
        {
            return mode != MODE.ERASE ? func() : null;
        }

        // action
        protected void P(Action action)
        {
            if (mode != MODE.ERASE) action();
        }

        // only in show mode
        protected void INIT(Action action)
        {
            if (mode == MODE.SHOW) action();
        }

        #endregion

        #region Nested type: DDThrow

        private class DDThrow : Exception
        {
        }

        #endregion
    }
}